﻿/**
         ************************************************************
         ***@project jquery瀑布流插件
         ***@author hcp0209@gmail.com
         ***@ver version 1.0
         ************************************************************
         column_width:204  //瀑布流是由列组成的，该参数规定了每列的宽度，该参数会直接影响到瀑布流的列数
         column_className:'waterfall_column'   //列的类名，便于自定义样式
         column_space:10    //列与列之间的间距
         cell_selector:'.cell'   //要排列的砖块的选择器，限定在瀑布流的容器内，即插件是通过这个选择器来获取砖块元素的,并且是在瀑布流的容器内来查找这个选择器匹配的元素。
         img_selector:'img'  //要加载的图片的选择器。如果你的瀑布流要加载的砖块元素的主题内容是大小不固定的图片，则该参数就是这些图片的选择器，插件需要获取这些图片来进行计算。
         auto_imgHeight:true  //是否需要自动计算图片的高度，如果图片的大小是固定的，则把该参数设为false吧
         fadein:true  //是否渐显载入
         fadein_speed:600  //渐显速率，单位毫秒
         insert_type:1  //砖块插入方式，1为插入最短那列，2为按序轮流插入
         getResource:function(index,render){ } //获取动态资源函数,必须返回一个砖块元素集合，传入的第一个参数index为已加载的次数，第二个参数为渲染函数，它可以接受一个砖头元素集合作为参数，如果是使用ajax加载数据，则得到数据后要手动调用该函数来进行渲染 。每次到达瀑布流底部时会自动触发该函数来加载更多资源。
         */
; (function ($) {
    var//参数
        setting = {
            column_width: 204,//列宽
            column_className: 'waterfall_column',//列的类名
            column_space: 10,//列间距
            cell_selector: '.cell',//要排列的砖块的选择器，context为整个外部容器
            img_selector: 'img',//要加载的图片的选择器
            auto_imgHeight: true,//是否需要自动计算图片的高度
            fadein: true,//是否渐显载入
            fadein_speed: 600,//渐显速率，单位毫秒
            insert_type: 1, //单元格插入方式，1为插入最短那列，2为按序轮流插入
            getResource: function (index) {
            }  //获取动态资源函数,必须返回一个砖块元素集合,传入参数为加载的次数
        },
        //
        waterfall = $.waterfall = {}, //对外信息对象
        isResize = $.isResize = true,
        isScroll = $.waterfall.isScroll = true,
        $container = null;//容器
    waterfall.load_index = 0, //加载次数
    $.fn.extend({
        waterfall: function (opt) {
            opt = opt || {};
            setting = $.extend(setting, opt);
            $container = waterfall.$container = $(this);
            waterfall.$columns = creatColumn();
            render($(this).find(setting.cell_selector).detach(), false); //重排已存在元素时强制不渐显
            waterfall._scrollTimer2 = null;
            $(window).bind('scroll', function () {
                clearTimeout(waterfall._scrollTimer2);
                waterfall._scrollTimer2 = setTimeout(onScroll, 300);
            });
            waterfall._scrollTimer3 = null;
            $(window).bind('resize', function () {
                clearTimeout(waterfall._scrollTimer3);
                waterfall._scrollTimer3 = setTimeout(onResize, 300);
            });
        },
        isResize: function (resize) { isResize = resize; },
        //isScroll: function (scroll) { isScroll = scroll; },
    });
    function creatColumn() {//创建列
        waterfall.column_num = calculateColumns();//列数
        //循环创建列
        var html = '';
        //alert(setting.column_space);
        for (var i = 0; i < waterfall.column_num; i++) {
            //html += '<div class="' + setting.column_className + '" style="width:' + setting.column_width + 'px; display:inline-block; *display:inline;zoom:1; margin-left:' + setting.column_space / 2 + 'px;margin-right:' + setting.column_space / 2 + 'px; vertical-align:top; overflow:hidden"></div>';
            html += '<div class="' + setting.column_className + '" style="width:' + setting.column_width + 'px;zoom:1; ' + (i == 0 ? ('margin-left:' + setting.column_space + 'px;') : '') + 'margin-right:' + setting.column_space + 'px; vertical-align:top; overflow:hidden;float:left;"></div>';
        }
        $container.prepend(html);//插入列
        return $('.' + setting.column_className, $container);//列集合
    }
    function calculateColumns() {//计算需要的列数
        var workWidth = document.body.clientWidth;
        //alert(waterfall.$container.width());
        //var v = (workWidth) / (setting.column_width + setting.column_space);
        var v = workWidth / setting.column_width;
        var num = Math.floor(v);
        var l = workWidth - setting.column_width * num;
        //alert(l);
        var space = l / (num + 1);
        if (space < 1) {
            num = num - 1;
            l = workWidth - setting.column_width * num;
            space = l / (num + 1);
        }
        
        //alert(num);
        setting.column_space = Math.floor(space);
        //alert(setting.column_space);
        if (num < 1) { num = 1; } //保证至少有一列
        //alert(((workWidth) % (setting.column_width * num)));
        return num;
    }
    function render(elements, fadein) {//渲染元素
        if (!$(elements).length) return;//没有元素
        var $columns = waterfall.$columns;
        $(elements).each(function (i) {
            if (!setting.auto_imgHeight || setting.insert_type == 2) {//如果给出了图片高度，或者是按顺序插入，则不必等图片加载完就能计算列的高度了
                if (setting.insert_type == 1) {
                    insert($(elements).eq(i), setting.fadein && fadein);//插入元素
                } else if (setting.insert_type == 2) {
                    insert2($(elements).eq(i), i, setting.fadein && fadein);//插入元素	 
                }
                return true;//continue
            }
            if ($(this)[0].nodeName.toLowerCase() == 'img' || $(this).find(setting.img_selector).length > 0) {//本身是图片或含有图片
                var image = new Image;
                var src = $(this)[0].nodeName.toLowerCase() == 'img' ? $(this).attr('src') : $(this).find(setting.img_selector).attr('src');
                image.onload = function () { //图片加载后才能自动计算出尺寸
                    image.onreadystatechange = null;
                    if (setting.insert_type == 1) {
                        insert($(elements).eq(i), setting.fadein && fadein); //插入元素
                    } else if (setting.insert_type == 2) {
                        insert2($(elements).eq(i), i, setting.fadein && fadein); //插入元素	 
                    }
                    image = null;
                };
                image.onreadystatechange = function () { //处理IE等浏览器的缓存问题：图片缓存后不会再触发onload事件
                    if (image.readyState == "complete") {
                        image.onload = null;
                        if (setting.insert_type == 1) {
                            insert($(elements).eq(i), setting.fadein && fadein); //插入元素
                        } else if (setting.insert_type == 2) {
                            insert2($(elements).eq(i), i, setting.fadein && fadein); //插入元素	 
                        }
                        image = null;
                    }
                };
                image.src = src;
            } else {//不用考虑图片加载
                if (setting.insert_type == 1) {
                    insert($(elements).eq(i), setting.fadein && fadein);//插入元素
                } else if (setting.insert_type == 2) {
                    insert2($(elements).eq(i), i, setting.fadein && fadein);//插入元素	 
                }
            }
        });
    }
    function public_render(elems) {//ajax得到元素的渲染接口
        render(elems, true);
    }
    function insert($element, fadein) {//把元素插入最短列
        if (fadein) {//渐显
            $element.css('opacity', 0).appendTo(waterfall.$columns.eq(calculateLowest())).fadeTo(setting.fadein_speed, 1);
        } else {//不渐显
            $element.appendTo(waterfall.$columns.eq(calculateLowest()));
        }
    }
    function insert2($element, i, fadein) {//按序轮流插入元素
        if (fadein) {//渐显
            $element.css('opacity', 0).appendTo(waterfall.$columns.eq(i % waterfall.column_num)).fadeTo(setting.fadein_speed, 1);
        } else {//不渐显
            $element.appendTo(waterfall.$columns.eq(i % waterfall.column_num));
        }
    }
    function calculateLowest() {//计算最短的那列的索引
        var min = waterfall.$columns.eq(0).outerHeight(), min_key = 0;
        waterfall.$columns.each(function (i) {
            if ($(this).outerHeight() < min) {
                min = $(this).outerHeight();
                min_key = i;
            }
        });
        return min_key;
    }
    function getElements() {//获取资源
        $.waterfall.load_index++;
        return setting.getResource($.waterfall.load_index, public_render);
    }
    waterfall._scrollTimer = null;//延迟滚动加载计时器
    function onScroll() {//滚动加载
        clearTimeout(waterfall._scrollTimer);
        waterfall._scrollTimer = setTimeout(function () {
            //var $lowest_column = waterfall.$columns.eq(calculateLowest());//最短列
            //var bottom = $lowest_column.offset().top + $lowest_column.outerHeight();//最短列底部距离浏览器窗口顶部的距离
            //var scrollTop = document.documentElement.scrollTop || document.body.scrollTop || 0;//滚动条距离
            //var windowHeight = document.documentElement.clientHeight || document.body.clientHeight || 0;//窗口高度
            //if (scrollTop >= bottom - windowHeight) {
            //    render(getElements(), true);
            //}
            var closeToBottom = $.waterfall.isScroll && ($(window).scrollTop() + $(window).height() > $(document).height() - 100);
            if (closeToBottom) {
                //alert(location.href);
                //alert(isScroll);
                render(getElements(), true);
            }

            //alert($.waterfall.isScroll);
            //isScroll = true;
        }, 100);
    }
    function onResize() {//窗口缩放时重新排列
        if (isResize) {
            setting.column_space = 1;
            waterfall.$container.css("width", "auto");
            if (calculateColumns() == waterfall.column_num) {
                $("." + setting.column_className).each(function (i, item) {
                    if (i == 0) {
                        $(this).css("margin-left", setting.column_space);
                    }
                    $(this).css("margin-right", setting.column_space);
                });
                return; //列数未改变，不需要重排
            }
            var $cells = waterfall.$container.find(setting.cell_selector);
            waterfall.$columns.remove();
            waterfall.$columns = creatColumn();
            render($cells, false); //重排已有元素时强制不渐显
            //alert(waterfall.$container.width());
            //alert("b");
        }
    }
})(jQuery);